package base

import (
	"bytes"
	"errors"
	"fmt"
	"strconv"
	"strings"
)

//DataFilter 数据过滤接口
type DataFilter interface {
	GetFilterColName() (string, error)
	SetAdditional(string, interface{})
	GetFilterKeys(pType string, userID int) (string, error)
}

//DefaultFilter 默认的数据过滤
type DefaultFilter struct {
	FilterColName string
	TableName     string
	EmidColName   string
	AcidColName   string
	WhereCause    string
	additionalMap map[string]interface{}
}

//GetFilterColName 获取要过滤的实体的字段名称
func (f *DefaultFilter) GetFilterColName() (string, error) {
	if f.FilterColName == "" {
		return "", errors.New("FilterColName不能为空！")
	}
	return f.FilterColName, nil
}

//SetAdditional 设置额外的属性
func (f *DefaultFilter) SetAdditional(name string, val interface{}) {
	if f.additionalMap == nil {
		f.additionalMap = make(map[string]interface{})
	}
	f.additionalMap[name] = val
}

//GetFilterKeys 获取指定权限类型和id可以查看的数据键值
func (f *DefaultFilter) GetFilterKeys(pType string, userID int) (string, error) {
	var sql string
	if pType == "G" {
		sql = fmt.Sprintf("select DPID from dim_user where emid=%d", userID)
		return sql, nil
	}
	if pType == "O" {
		sql = fmt.Sprintf("SELECT OrganID FROM V_ParentOrgan WHERE ParentOrganID IN (select PDID from dim_user where emid=%d)", userID)
		return sql, nil
	}
	if f.TableName == "" {
		if f.FilterColName == f.EmidColName {
			if pType == "3" {
				sql = fmt.Sprintf("select id from t_sysuser where OrganId in (select OrganId from t_sysuser where id=%d)", userID)
			} else if pType == "J" {
				sql = fmt.Sprintf("select emid from dim_user where PDID in (select PDID from dim_user where emid=%d)", userID)
			} else {
				sql = fmt.Sprintf("%d", userID)
			}
		}
		return sql, nil
	}
	if f.EmidColName == "" {
		return "", errors.New("EmidColName不能为空！")
	}
	if f.AcidColName == "" {
		return "", errors.New("AcidColName不能为空！")
	}
	var buff bytes.Buffer
	tName := strings.ToUpper(f.TableName)
	if tName == "T_COMP_ACCO_DIVI" || tName == "T_INDI_ACCO_DIVI" || tName == "T_INDI_LOAN_DIVI" {
		tName = tName + "_CURR"
	}
	buff.WriteString("select distinct ")
	buff.WriteString(f.AcidColName)
	buff.WriteString(" from ")
	buff.WriteString(tName)
	buff.WriteString(" where  ")
	buff.WriteString(f.EmidColName)
	if pType == "3" {
		buff.WriteString(fmt.Sprintf(" in  (select id from t_sysuser where OrganId in (select OrganId from t_sysuser where id=%d))", userID))
	} else if pType == "J" {
		buff.WriteString(fmt.Sprintf(" in  (select emid from dim_user where PDID in (select PDID from dim_user where emid=%d))", userID))
	} else {
		buff.WriteString(fmt.Sprintf(" = %d ", userID))
	}
	if f.WhereCause != "" {
		buff.WriteString(" and  ")
		buff.WriteString(f.WhereCause)
	}
	return buff.String(), nil
}

//WorkFolowFilter 流程的数据过滤
type WorkFolowFilter struct {
	FilterColName string
	additionalMap map[string]interface{}
}

//GetFilterColName 获取要过滤的实体的字段名称
func (f *WorkFolowFilter) GetFilterColName() (string, error) {
	if f.FilterColName == "" {
		return "", errors.New("FilterColName不能为空！")
	}
	return f.FilterColName, nil
}

//SetAdditional 设置额外的属性
func (f *WorkFolowFilter) SetAdditional(name string, val interface{}) {
	if f.additionalMap == nil {
		f.additionalMap = make(map[string]interface{})
	}
	f.additionalMap[name] = val
}

//GetFilterKeys 获取指定权限类型和id可以查看的数据键值
func (f *WorkFolowFilter) GetFilterKeys(pType string, userID int) (string, error) {
	var sql string
	flowType := ToString(f.additionalMap["flowType"])
	if flowType == "" {
		flowType = "all"
	}
	aper := f.additionalMap["appointer"]
	aperSteps := make([]string, 0, 5)
	uIDStr := strconv.Itoa(userID)
	if apMap, ok := aper.(map[int][]string); ok {
		for k, v := range apMap {
			if IsInSlice(v, uIDStr) {
				aperSteps = append(aperSteps, strconv.Itoa(k))
			}
		}
	}
	reco := f.additionalMap["recorder"]
	isReco := false
	if recoArr, ok := reco.([]string); ok {
		if recoArr != nil && IsInSlice(recoArr, uIDStr) {
			isReco = true
		}
	}
	managers := ""
	if f.additionalMap["manager"] != nil {
		managers = ToString(f.additionalMap["manager"])
	}
	isMg := false
	mgWfids := make([]string, 0, 3)
	if managers != "" {
		mArr := strings.Split(managers, ",")
		for _, m := range mArr {
			wfrls := strings.Split(m, ":")
			if len(wfrls) != 2 {
				return "", fmt.Errorf("错误的manager附加属性%s，格式应该为wfid:roleid,roleid:wfid:roleid", managers)
			}
			if wfrls[0] == "" || wfrls[1] == "" {
				continue
			}
			sql = "select COUNT(*) from t_UserRole WHERE USERID=? AND ROLEID IN (?)"
			row := DB.Raw(sql, userID, wfrls[1]).Row()
			var count int
			row.Scan(&count)
			if count > 0 {
				isMg = true
				mgWfids = append(mgWfids, wfrls[0])
			}
		}
	}
	wfid := ToString(f.additionalMap["wfid"])
	if isMg {
		pType = "4"
		wfid = strings.Join(mgWfids, ",")
	}
	if len(aperSteps) == 0 && !isReco {
		if flowType == "apply" {
			sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and stepid=1", userID)
		} else if flowType == "doing" {
			sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and state in ('0','1') and stepid>1", userID)
		} else if flowType == "done" {
			sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and state = '2'  and stepid>1", userID)
		} else if flowType == "firstdoing" {
			sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and state in ('0','1') and stepid=1", userID)
		} else if flowType == "firstdone" {
			sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and state = '2'  and stepid=1", userID)
		} else if flowType == "manager" {
			if isMg {
				sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s) and state in ('0','2')", wfid)
			} else {
				sql = "select id from t_flow_run where wfid=-1"
			}
		} else if flowType == "history" {
			if pType == "3" {
				sql = fmt.Sprintf("select runid from T_FLOW_RUN_STEP_BAK where emid in (select id from t_sysuser where OrganId = (select OrganId from t_sysuser where emid=%d)) and stepid>1", userID)
			} else if pType == "1" {
				sql = fmt.Sprintf("select runid from T_FLOW_RUN_STEP_BAK where emid=%d and stepid>1", userID)
			} else {
				sql = fmt.Sprintf("select id from T_FLOW_RUN_BAK where wfid in (%s) ", wfid)
			}
		} else if flowType == "firsthistory" {
			if pType == "3" {
				sql = fmt.Sprintf("select runid from T_FLOW_RUN_STEP_BAK where emid in (select id from t_sysuser where OrganId = (select OrganId from t_sysuser where emid=%d)) and stepid=1", userID)
			} else if pType == "1" {
				sql = fmt.Sprintf("select runid from T_FLOW_RUN_STEP_BAK where emid=%d and stepid=1", userID)
			} else {
				sql = fmt.Sprintf("select id from T_FLOW_RUN_BAK where wfid in (%s) ", wfid)
			}
		} else if flowType == "firstall" {
			if pType == "3" {
				sql = fmt.Sprintf("select runid from t_flow_run_step where emid in (select id from t_sysuser where OrganId = (select OrganId from t_sysuser where emid=%d)) and stepid=1", userID)
			} else if pType == "1" {
				sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and stepid=1", userID)
			} else {
				sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s) ", wfid)
			}
		} else {
			if pType == "3" {
				sql = fmt.Sprintf("select runid from t_flow_run_step where emid in (select id from t_sysuser where OrganId = (select OrganId from t_sysuser where emid=%d)) and stepid>1", userID)
			} else if pType == "1" {
				sql = fmt.Sprintf("select runid from t_flow_run_step where emid=%d and stepid>1", userID)
			} else {
				sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s) ", wfid)
			}
		}

	} else if isReco {
		sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s) and stat = '1'", wfid)
	} else {
		stepStr := strings.Join(aperSteps, ",")
		if flowType == "doing" {
			sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s) and step in (%s)", wfid, stepStr)
		} else if flowType == "done" {
			sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s) and step not in (%s)", wfid, stepStr)
		} else {
			sql = fmt.Sprintf("select id from t_flow_run where wfid in (%s)", wfid)
		}
	}
	return sql, nil
}

func (f *DefaultFilter) execSQL(sql string, id int) ([]int, error) {
	rows, err := DB.Raw(sql, id).Rows()
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	acids := make([]int, 0, 10)
	for rows.Next() {
		var acid int
		err = rows.Scan(&acid)
		if err != nil {
			return nil, err
		}
		acids = append(acids, acid)
	}
	return acids, nil
}
